/***********************************************************************
  * @代码说明：本代码内容用于快速使用DHT11
  * @作者：梁莅
  * @日期：2020/07/30
  * @开发指导：wiki.stduino.com
  ***********************************************************************/
/* Includes ------------------------------------------------------------------*/
//例如：#include "stm32f10x_abc.h"
/*上面不用动，开始你的表演 ------------------------------------------------------------------*/

#include "DHT11.h"
#include <math.h>
//****************************************************
//初始化
//****************************************************
DHT11::DHT11(uint8_t p)
{
    pin=p;
}

DHT11::~DHT11()
{
    ;
}

//****************************************************
//读取数据，包括温度、湿度以及校验码
//****************************************************
int DHT11::read(void)
{
 uint8_t bits[5];
 uint8_t cnt = 7;
 uint8_t idx = 0;
 
 //bits[5]全部置为0
 for (int i=0; i< 5; i++)
 {
  bits[i] = 0;
 }
 
 //微处理器发出开始信号
 pinMode(pin, OUTPUT);
 digitalWrite(pin, LOW);//低电平18ms开始
 delay(18);
 digitalWrite(pin, HIGH);
 
 //等待应答
 delayMicroseconds(40);
 pinMode(pin, INPUT);//上拉电阻输入
 
 unsigned int loopCnt = micros();
 
 while(digitalRead(pin) == LOW)//DHT11低电平应答，83微秒
 {
  if ((micros() - loopCnt) >= 90) 
  {
   
   return DHTLIB_ERROR_TIMEOUT;
  }
 }
 
 loopCnt = micros();
 Serial.println(loopCnt);
 while(digitalRead(pin) == HIGH)//DHT11高电平结束应答，准备发送信号，87微秒
 {
  if ((micros() - loopCnt) >= 1200)
  {
   Serial.println(micros());
   return DHTLIB_ERROR_TIMEOUT;
  }
 }
 
 //接收40bit数据
 for (int i=0; i<40; i++)
 {
  loopCnt = micros();
  
  while(digitalRead(pin) == LOW)//数据1或0以低电平开始，约54微秒
  {
   if ((micros() - loopCnt) >= 60) 
   {

    return DHTLIB_ERROR_TIMEOUT;//超时
   }
  }
  
  unsigned long t = micros();//程序已运行时间
  loopCnt = micros();
  
  while(digitalRead(pin) == HIGH)//数据0或1的另一半高电平信号，其中数据0为23-27微秒，数据1为68到74微秒
  {
   if ((micros() - loopCnt) >= 80) 
   {

    return DHTLIB_ERROR_TIMEOUT;//超时
   }
  }
  
  if ((micros() - t) > 40) //如果大于40，则为数据1，反之为0
  {
   bits[idx] |= (1 << cnt);//数据存到cnt位(从bit7开始)
  }
  if (cnt == 0)//八位数据传输结束
  {
   cnt = 7;//下一个bits从第七位开始存储
   idx++;//下一个bits序号
  }else  //如果传输没有结束
  {
   cnt--;
  }
 }
 
 
 humidity= bits[0] + (bits[1] & 0x0f) * 0.1;
 temperature=bits[2];
 temperature += (bits[3] & 0x0f) * 0.1;
 if (bits[3] & 0x80) //判断温度是否低于0℃
    {
        temperature =  - temperature;
    }
    
 uint8_t sum=bits[0] + bits[1] + bits[2] + bits[3];
 
 if(bits[4] != sum)//校验码检查
 {
  return DHTLIB_ERROR_CHECKSUM;//校验错误
 }
 
 return DHTLIB_OK;
}

//****************************************************
//摄氏温度转华氏温度
//****************************************************
double Fahrenheit(double celsius)
{
    return 1.8 * celsius + 32;
}
//****************************************************
//摄氏温度转化为热力学温度
//****************************************************
double Kelvin(double celsius)
{
    return celsius + 273.15;
}
//****************************************************
//露点（在此温度时，空气饱和并产生露珠）
//****************************************************
double dewPoint(double celsius, double humidity)
{
    double A0= 373.15/(273.15 + celsius);
    double SUM = -7.90298 * (A0-1);
    SUM += 5.02808 * log10(A0);
    SUM += -1.3816e-7 * (pow(10, (11.344*(1-1/A0)))-1) ;
    SUM += 8.1328e-3 * (pow(10,(-3.49149*(A0-1)))-1) ;
    SUM += log10(1013.246);
    double VP = pow(10, SUM-3) * humidity;
    double T = log(VP/0.61078);   
    return (241.88 * T) / (17.558-T);
} 
//****************************************************
//快速计算露点（点在此温度时，空气饱和并产生露珠）
//****************************************************
double dewPointFast(double celsius, double humidity)
{
    double a = 17.271;
    double b = 237.7;
    double temp = (a * celsius) / (b + celsius) + log(humidity/100);
    double Td = (b * temp) / (a - temp);
    return Td;
}

//****************************************************
//错误检查
//****************************************************
void check(DHT11 dht11)
{
    int chk=dht11.read();
    Serial.println("------------");//打印出"------------"
    Serial.print("错误检查:");
    switch (chk)
    {
    case DHTLIB_OK:
        Serial.println("检查正确");
        break;
    case DHTLIB_ERROR_CHECKSUM:
        Serial.println("校验错误");
        break;
    case DHTLIB_ERROR_TIMEOUT:
        Serial.println("超时错误");
        break;
    default:
        Serial.println("未知错误");
        break;
    }
}